/**
 ******************************************************************************
 * @file           : bsp_oled.c
 * @brief          : OLED Display Driver Implementation (STM32H7xx)
 ******************************************************************************
 * @attention
 *
 * OLED显示屏驱动程序实现文件
 * SSD1306芯片
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./Devices/OLED/bsp_oled.h"
#include "./Devices/OLED/bsp_oled_config.h"

/* Private includes ----------------------------------------------------------*/
#include <string.h>

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define OLED_CMD        0x00    /* 命令 */
#define OLED_DATA       0x01    /* 数据 */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static uint8_t sg_oled_buffer[OLED_WIDTH * OLED_PAGES];  /* 显示缓冲区 */

/* 字库（8x16） */
static const uint8_t sg_font_8x16[][16] = {
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 空格
    // ... 这里应该包含完整的ASCII字库
};

/* Private function prototypes -----------------------------------------------*/
static OLED_Error_e oled_write_byte(uint8_t data, uint8_t cmd);
static OLED_Error_e oled_write_command(uint8_t cmd);
static OLED_Error_e oled_write_data(uint8_t data);
static uint32_t oled_pow(uint8_t x, uint8_t y);

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       初始化OLED
 */
void oled_init(void)
{
    HAL_Delay(100);  /* 等待OLED上电稳定 */
    
    /* 初始化命令序列 */
    oled_write_command(0xAE);  /* 关闭显示 */
    
    oled_write_command(0xD5);  /* 设置时钟分频 */
    oled_write_command(0x80);
    
    oled_write_command(0xA8);  /* 设置多路复用率 */
    oled_write_command(0x3F);
    
    oled_write_command(0xD3);  /* 设置显示偏移 */
    oled_write_command(0x00);
    
    oled_write_command(0x40);  /* 设置起始行 */
    
    oled_write_command(0x8D);  /* 电荷泵 */
    oled_write_command(0x14);
    
    oled_write_command(0x20);  /* 内存寻址模式 */
    oled_write_command(0x00);  /* 水平寻址 */
    
    oled_write_command(0xA1);  /* 段重映射 */
    oled_write_command(0xC8);  /* COM扫描方向 */
    
    oled_write_command(0xDA);  /* COM引脚配置 */
    oled_write_command(0x12);
    
    oled_write_command(0x81);  /* 对比度 */
    oled_write_command(0xCF);
    
    oled_write_command(0xD9);  /* 预充电周期 */
    oled_write_command(0xF1);
    
    oled_write_command(0xDB);  /* VCOMH电压 */
    oled_write_command(0x40);
    
    oled_write_command(0xA4);  /* 全局显示开启 */
    oled_write_command(0xA6);  /* 正常显示 */
    
    oled_clear();
    oled_write_command(0xAF);  /* 开启显示 */
    
    log_i("OLED初始化完成");
}

/**
 * @brief       清屏
 */
void oled_clear(void)
{
    memset(sg_oled_buffer, 0, sizeof(sg_oled_buffer));
    oled_refresh();
}

/**
 * @brief       开启显示
 */
void oled_display_on(void)
{
    oled_write_command(0x8D);  /* 电荷泵使能 */
    oled_write_command(0x14);
    oled_write_command(0xAF);  /* 开启显示 */
}

/**
 * @brief       关闭显示
 */
void oled_display_off(void)
{
    oled_write_command(0x8D);  /* 电荷泵关闭 */
    oled_write_command(0x10);
    oled_write_command(0xAE);  /* 关闭显示 */
}

/**
 * @brief       设置显示模式
 *
 * @param[in]   mode: 显示模式
 */
void oled_set_display_mode(OLED_DisplayMode_e mode)
{
    if (mode == OLED_MODE_INVERSE)
    {
        oled_write_command(0xA7);  /* 反色显示 */
    }
    else
    {
        oled_write_command(0xA6);  /* 正常显示 */
    }
}

/**
 * @brief       设置像素点
 *
 * @param[in]   x: X坐标（0~127）
 * @param[in]   y: Y坐标（0~63）
 * @param[in]   on: true=点亮, false=熄灭
 */
void oled_set_pixel(uint8_t x, uint8_t y, bool on)
{
    uint8_t page, bit;
    uint16_t index;
    
    if (x >= OLED_WIDTH || y >= OLED_HEIGHT)
    {
        return;
    }
    
    page = y / 8;
    bit = y % 8;
    index = page * OLED_WIDTH + x;
    
    if (on)
    {
        sg_oled_buffer[index] |= (1 << bit);
    }
    else
    {
        sg_oled_buffer[index] &= ~(1 << bit);
    }
}

/**
 * @brief       显示字符
 *
 * @param[in]   x: X坐标
 * @param[in]   y: Y坐标
 * @param[in]   ch: 字符
 * @param[in]   font_size: 字体大小（8/16）
 */
void oled_show_char(uint8_t x, uint8_t y, char ch, uint8_t font_size)
{
    uint8_t i, j;
    uint8_t temp;
    uint8_t page = y / 8;
    uint8_t index = ch - ' ';  /* 获取字符索引 */
    
    if (font_size == 16)  /* 8x16字体 */
    {
        for (i = 0; i < 8; i++)
        {
            /* 上半部分 */
            temp = sg_font_8x16[index][i];
            for (j = 0; j < 8; j++)
            {
                oled_set_pixel(x + i, y + j, temp & 0x01);
                temp >>= 1;
            }
            
            /* 下半部分 */
            temp = sg_font_8x16[index][i + 8];
            for (j = 0; j < 8; j++)
            {
                oled_set_pixel(x + i, y + 8 + j, temp & 0x01);
                temp >>= 1;
            }
        }
    }
}

/**
 * @brief       显示字符串
 *
 * @param[in]   x: X坐标
 * @param[in]   y: Y坐标
 * @param[in]   str: 字符串
 * @param[in]   font_size: 字体大小
 */
void oled_show_string(uint8_t x, uint8_t y, const char *str, uint8_t font_size)
{
    uint8_t offset = 0;
    
    while (*str != '\0')
    {
        oled_show_char(x + offset, y, *str, font_size);
        offset += 8;  /* 字符宽度 */
        str++;
    }
}

/**
 * @brief       显示数字
 *
 * @param[in]   x: X坐标
 * @param[in]   y: Y坐标
 * @param[in]   num: 数字
 * @param[in]   len: 显示长度
 * @param[in]   font_size: 字体大小
 */
void oled_show_number(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t font_size)
{
    uint8_t i;
    uint8_t temp;
    
    for (i = 0; i < len; i++)
    {
        temp = (num / oled_pow(10, len - i - 1)) % 10;
        oled_show_char(x + i * 8, y, temp + '0', font_size);
    }
}

/**
 * @brief       刷新显示
 */
void oled_refresh(void)
{
    uint8_t page, i;
    
    for (page = 0; page < OLED_PAGES; page++)
    {
        oled_write_command(0xB0 + page);  /* 设置页地址 */
        oled_write_command(0x00);          /* 设置列低地址 */
        oled_write_command(0x10);          /* 设置列高地址 */
        
        for (i = 0; i < OLED_WIDTH; i++)
        {
            oled_write_data(sg_oled_buffer[page * OLED_WIDTH + i]);
        }
    }
}

/**
 * @brief       刷新指定区域
 */
void oled_refresh_area(uint8_t x, uint8_t y, uint8_t width, uint8_t height)
{
    /* 预留接口，可根据需要实现局部刷新 */
    oled_refresh();
}

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       写入字节
 */
static OLED_Error_e oled_write_byte(uint8_t data, uint8_t cmd)
{
#if (OLED_USE_I2C == 1)
    uint8_t buf[2];
    buf[0] = cmd ? OLED_DATA : OLED_CMD;
    buf[1] = data;
    
    #if (OLED_USE_BSP_DRIVER == 1)
        return (iic_write(OLED_I2C_ADDR, buf, 2) == IIC_OK) ? OLED_OK : OLED_ERROR;
    #else
        if (HAL_I2C_Master_Transmit(OLED_I2C_HANDLE, OLED_I2C_ADDR, buf, 2, 100) == HAL_OK)
        {
            return OLED_OK;
        }
        return OLED_ERROR;
    #endif
#else
    /* SPI模式 */
    HAL_GPIO_WritePin(OLED_DC_GPIO_PORT, OLED_DC_GPIO_PIN, cmd ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(OLED_CS_GPIO_PORT, OLED_CS_GPIO_PIN, GPIO_PIN_RESET);
    
    #if (OLED_USE_BSP_DRIVER == 1)
        spi_write(&data, 1);
    #else
        HAL_SPI_Transmit(OLED_SPI_HANDLE, &data, 1, 100);
    #endif
    
    HAL_GPIO_WritePin(OLED_CS_GPIO_PORT, OLED_CS_GPIO_PIN, GPIO_PIN_SET);
    return OLED_OK;
#endif
}

/**
 * @brief       写入命令
 */
static OLED_Error_e oled_write_command(uint8_t cmd)
{
    return oled_write_byte(cmd, OLED_CMD);
}

/**
 * @brief       写入数据
 */
static OLED_Error_e oled_write_data(uint8_t data)
{
    return oled_write_byte(data, OLED_DATA);
}

/**
 * @brief       计算x的y次方
 */
static uint32_t oled_pow(uint8_t x, uint8_t y)
{
    uint32_t result = 1;
    while (y--)
    {
        result *= x;
    }
    return result;
}
